/**
 * 
 */
package org.mhz.ootw.service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.mhz.ootw.annotation.LogTimeTaken;
import org.mhz.ootw.tree.Attributes;
import org.mhz.ootw.tree.JsTree;
import org.mhz.ootw.tree.JsTreeNode;
import org.mhz.ootw.util.Constants;
import org.mhz.ootw.util.Ellipsis;
import org.mhz.ootw.util.JsTreeHelper;
import org.mhz.ootw.util.SolrServerHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * @author Mahan
 *
 * Text search service
 */
@Service(Constants.TEXT_SEARCH_SERVICE)
public class TextSearchService implements SearchService
{
    private static final Logger LOGGER = LoggerFactory.getLogger(TextSearchService.class);

    /* (non-Javadoc)
     * @see org.mhz.ootw.service.SearchService#getSearchResults(java.lang.String)
     */
    @Override
    @LogTimeTaken
    public String getSearchResults(final String aSearchText, final String aSearchItems)
    {      
        final JsTree jsTree = new JsTree();
        List<JsTreeNode> rootTreeNodes = null;
        List<JsTreeNode> parentsChildren = null;
        List<JsTreeNode> readableItemsChildren = null;
        
        final Map<String, String> alreadySetCountFields = new HashMap<String, String>();
        
        final String[] facetFields = {Constants.READABLE_ITEM};
 
        final QueryResponse response = getSolrResponse(aSearchText, aSearchItems, facetFields);
        final SolrDocumentList documents = response.getResults();            

        final List<FacetField> facetFieldsList = response.getFacetFields();

        final Map<String, String> highlightedContents = getHighlighting(response.getHighlighting());
        String readableItemTitle = "";

        for (SolrDocument document : documents) 
        {
            final String id = (String) document.get(Constants.ID);
            //final String content = (String) document.get("content");
            final String highlightedContent = highlightedContents.get(id);
            final String readableItem = (String) document.get(Constants.READABLE_ITEM);
            final String readableItemName = (String) document.get(Constants.READABLE_ITEM_NAME);
            final String parent = (String) document.get(Constants.PARENT);
            
            // If the readable item has already has its count set then
            // simply get it from the map.
            // Otherwise set it.
            if (alreadySetCountFields.containsKey(readableItem))
            {                                        
                readableItemTitle = alreadySetCountFields.get(readableItem);
            }
            else
            {
                readableItemTitle = JsTreeHelper.setFacetFieldCount(facetFieldsList, 
                                                                    readableItem, 
                                                                    readableItemName);
                alreadySetCountFields.put(readableItem, readableItemTitle);
            }
            
            // Get the parent node if it exists
            JsTreeNode parentNode = JsTreeHelper.getNodeIfExists(jsTree.getRootNodes(), parent);                
            
            // Get the root tree nodes
            rootTreeNodes = jsTree.getRootNodes();   
                            
            // If the parent node doesn't exist then create it
            // and add it to the root tree
            if (parentNode == null)
            {
                parentNode = new JsTreeNode(parent, Constants.OPEN_STATE);  
                rootTreeNodes.add(parentNode);
            }
            
            // Get the children of the parent node
            parentsChildren = parentNode.getChildren();

            // Get the child node if it exists
            JsTreeNode childNode = JsTreeHelper.getNodeIfExists(parentsChildren, readableItemTitle);
            
            // If the child node does not exist then create it
            // and add it to the parents children
            if (childNode == null)
            {                    
                childNode = new JsTreeNode(readableItemTitle, Constants.OPEN_STATE);
                parentsChildren.add(childNode); 
            }                
            
            // Get the children of the readable item
            readableItemsChildren = childNode.getChildren();
            
            final String escapedContent = StringEscapeUtils.escapeJava(highlightedContent);
            final String contentDisplayText = 
                    Ellipsis.getShortenedTextNoHighlight(escapedContent, Constants.MAX_ELLIPSIS_LENGTH);
            
            // Create the readable item node
            final JsTreeNode readableItemChildNode = new JsTreeNode(contentDisplayText, null);
            readableItemChildNode.setAttributes(new Attributes(id, escapedContent, readableItem));
                            
            // Add the readable item node to the children 
            // of readable items
            readableItemsChildren.add(readableItemChildNode);                                                    
        }      
        
        return jsTree.jsonString();
    }
    
    /**
     * @param aHighlightingMap - The highlighting map
     * @return The map of highlighted contents
     */
    public Map<String, String> getHighlighting(final Map<String, Map<String,List<String>>> aHighlightingMap)
    {
        final Map<String, String> highlightedContents = new HashMap<String, String>();

        if (MapUtils.isNotEmpty(aHighlightingMap))
        {
            for (Map.Entry<String, Map<String,List<String>>> entry : aHighlightingMap.entrySet())
            {
                final String highlightId = entry.getKey();
                final Map<String,List<String>> highlightValue = entry.getValue();
                                
                if (MapUtils.isNotEmpty(highlightValue))
                {
                    for (Map.Entry<String, List<String>> valueEntry : highlightValue.entrySet())
                    {
                        //final String highlightValueId = valueEntry.getKey();
                        final List<String> highlightValuesList = valueEntry.getValue();     
                        
                        if (CollectionUtils.isNotEmpty(highlightValuesList))
                        {
                            for (String contentValue : highlightValuesList)
                            {
                                if (StringUtils.isNotBlank(contentValue))
                                {
                                    highlightedContents.put(highlightId, contentValue);
                                }
                            }
                        }
                    }
                }
            }
        }
        
        return highlightedContents;
    }
    
    /**
     * Get the Solr response
     *
     * @param aSearchText - The text to search
     * @param aSearchItems - The items to search in
     * @param aFacetFields - The facet fields
     * @return The solr response
     */
    public QueryResponse getSolrResponse(final String aSearchText, 
                                         final String aSearchItems,
                                         final String[] aFacetFields)
    {
        QueryResponse response = null;
        
        try
        {
            final SolrServer solrServer = SolrServerHelper.getInstance();
            
            final SolrQuery query = new SolrQuery(aSearchText);
            query.addFilterQuery(Constants.READABLE_ITEM + ":(" + aSearchItems + ")");
            query.addFacetField(aFacetFields);
            query.addHighlightField(Constants.CONTENT);
            query.setRows(Constants.MAX_SEARCH_ROWS);
            response = solrServer.query(query); 
        }
        catch (SolrServerException solrServerEx)
        {
            LOGGER.error("Error initializing SOLR server", solrServerEx);           
        }        
            
        return response;
    }
}
